<template>
  <div>
    <el-switch
      v-model="draggable" active-text="开启拖拽" inactive-text="关闭拖拽">
    </el-switch>
    <el-button v-if="draggable" @click="batchSave">批量保存</el-button>
    <el-button  type="danger" @click="batchDelete">批量删除</el-button>
    <el-tree :data="menus"
             :props="defaultProps"
             @node-click="handleNodeClick"
             show-checkbox
             node-key="catId"
             :expand-on-click-node="false"
             @node-drop="handleDrop"
             :draggable="draggable"
             :allow-drop="allowDrop"
             :default-expanded-keys="parentIds"
             ref="menuTree"
    >
            <span class="custom-tree-node" slot-scope="{ node, data }">
              <span>{{ node.label }}</span>
              <span>
                <el-button v-if="node.level <=2"
                           type="text"
                           size="mini"
                           @click="() => append(data)">
                  新增
                </el-button>
                 <el-button
                   type="text"
                   size="mini"
                   @click="() => edit(data)">
                  编辑
                </el-button>
                <el-button v-if="node.childNodes.length == 0"
                           type="text"
                           size="mini"
                           @click="() => remove(node, data)">
                  删除
                </el-button>
              </span>
            </span>
    </el-tree>
    <el-dialog
      :title="title"
      :visible.sync="dialogVisible"
      :close-on-click-modal="false"
      width="30%">
      <el-form :model="category">
        <el-form-item label="分类名称">
          <el-input v-model="category.name" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item label="图标">
          <el-input v-model="category.icon" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item label="计量单位">
          <el-input v-model="category.productUnit" autocomplete="off"></el-input>
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
      <el-button @click="dialogVisible = false">取 消</el-button>
      <el-button type="primary" @click="submitData">确 定</el-button>
    </span>
    </el-dialog>
  </div>
</template>

<script>
  export default {
    //import引入的组件需要注入到对象中才能使用",
    components: {},
    data () {
      return {
        pId: [],
        draggable: false,
        updateNodes: [],
        maxLen: 0,
        title: '',
        dialogType: '',
        menus: [],
        parentIds: [],
        dialogVisible: false,
        // form绑定的数据
        category: {
          catId: null,
          name: '',
          parentCid: 0,
          catLevel: 0,
          showStatus: 1,
          sort: 0,
          icon: '',
          productUnit: ''
        },
        defaultProps: {
          children: 'children',
          label: 'name'
        }
      }
    },
    methods: {
      handleNodeClick (data) {
        console.log(data)
      },
      // 获取所有的菜单及子菜单
      getMenu () {
        this.dataListLoading = true
        this.$http({
          url: this.$http.adornUrl('/product/category/list/tree'),
          method: 'get'
        }).then(({data}) => {
          this.menus = data.data
        })
      },

      // 增加菜单
      append (data) {
        console.log('append:', data)
        this.dialogVisible = true
        this.dialogType = 'add'
        this.title = '添加分类'
        this.category.parentCid = data.catId
        this.category.catLevel = data.catLevel * 1 + 1
        this.category.name = ''
        this.category.catId = null
        this.category.icon = ''
        this.category.productUnit = ''
      },

      // 编辑菜单
      edit (data) {
        console.log('edit:', data)
        this.dialogVisible = true
        this.dialogType = 'edit'
        this.title = '编辑分类'
        // 获取最新的数据库数据
        this.$http({
          url: this.$http.adornUrl(`/product/category/info/${data.catId}`),
          method: 'get'
        }).then(({data}) => {
          // 拿出最新要回显的数据
          this.category.name = data.data.name
          this.category.catId = data.data.catId
          this.category.icon = data.data.icon
          this.category.productUnit = data.data.productUnit
        })
      },

      submitData () {
        if (this.dialogType == 'add') {
          console.log('add...')
          this.addCategory()
        }
        if (this.dialogType == 'edit') {
          console.log('edit...')
          this.editCategory()
        }
      },

      // 添加菜单
      addCategory () {
        console.log('保存的数据', this.category)
        this.$http({
          url: this.$http.adornUrl('/product/category/save'),
          method: 'POST',
          data: this.$http.adornData(this.category, false)
        }).then(({data}) => {
          this.dialogVisible = false
          // 添加成功重新刷新tree数据
          this.$message({
            type: 'success',
            message: '菜单添加成功!'
          })
          // 删除成功后重新刷新tree
          this.getMenu()
          this.parentIds = [this.category.parentCid]
        })
      },

      editCategory () {
        console.log('修改的数据', this.category)
        // {} 解构出需要提交的数据
        var {name, catId, icon, productUnit} = this.category
        this.$http({
          url: this.$http.adornUrl('/product/category/update'),
          method: 'POST',
          data: this.$http.adornData({name, catId, icon, productUnit}, false)
        }).then(({data}) => {
          this.dialogVisible = false
          // 添加成功重新刷新tree数据
          this.$message({
            type: 'success',
            message: '菜单添加成功!'
          })
          // 删除成功后重新刷新tree
          this.getMenu()
          this.parentIds = [this.category.parentCid]
        })
      },

      // 删除菜单
      remove (node, data) {
        console.log('remove', node, data)
        var ids = [data.catId]
        this.$confirm(`是否删除【${data.name}】菜单`, '提示', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning'
        }).then(() => {
          this.$http({
            url: this.$http.adornUrl('/product/category/removeMenu'),
            method: 'POST',
            data: this.$http.adornData(ids, false)
          }).then(({data}) => {
            this.$message({
              type: 'success',
              message: '菜单删除成功!'
            })

            // 删除成功后重新刷新tree
            this.getMenu()

            // 定位在删除节点
            this.parentIds = [node.parent.data.catId]
          })
        }).catch(() => {
        })
      },

      // 判断是否可拖拽【不好理解】
      allowDrop (draggingNode, dropNode, type) {
        console.log('draggingNode：', draggingNode, dropNode, type)
        // 遍历计算当前节点的最大深度
        this.countMaxLen(draggingNode)
        let deep = Math.abs(this.maxLen - draggingNode.level) + 1
        console.log('最大deep: ', deep)
        // 判断当前拖拽节点的最大深度+父节点的层级不大于3即可

        if (type == 'inner') {
          // 如果是拖拽到目标层级里面，判断deep和目标层级的层级和不大于3
          return (deep + dropNode.level) <= 3
        } else {
          // 如果是拖拽到目标层级的前后的话，直接判断当前层级和deep的和 不大于3即可
          return (deep + dropNode.parent.level) <= 3
        }
      },

      // 计算节点的最大深度
      countMaxLen (node) {
        if (node.childNodes != null && node.childNodes.length > 0) {
          for (let i = 0; i < node.childNodes.length; i++) {
            if (node.childNodes[i].level > this.maxLen) {
              this.maxLen = node.childNodes[i].level
            }
            // 递归计算当前拖拽节点的最大深度
            this.countMaxLen(node.childNodes[i])
          }
        } else {
          // 如果没有子节点，最大深度就是当前的level
          this.maxLen = node.level
        }
      },

      /**
       * 处理拖拽结束后触发事件 拖拽后顺序的变化，父ID的变化，层级的变化
       * @param draggingNode 拖拽的节点
       * @param dropNode 目标节点
       * @param dropType 目标节点的类型
       * @param ev
       */
      handleDrop (draggingNode, dropNode, dropType, ev) {
        //console.log('tree drop: ', draggingNode, dropNode, dropType)
        let pId = 0// 最新父ID
        let silblings = null// 最新子元素【拖拽后的子元素数据】
        if (dropType == 'before' || dropType == 'after') {
          pId = dropNode.parent.data.catId == undefined ? 0 : dropNode.parent.data.catId // 避免before后父节点为数组的情况，undefined
          silblings = dropNode.parent.childNodes
        } else {
          pId = dropNode.data.catId
          silblings = dropNode.childNodes
        }
        console.log('最新数据：', pId, silblings)
        this.pId.push(pId)
        // 当前拖拽节点的最新排序
        for (let i = 0; i < silblings.length; i++) {
          // 如果遍历的是当前正在拖拽的节点
          if (silblings[i].data.catId == draggingNode.data.catId) {
            // 更改最新层级信息
            let catLevel = draggingNode.level// 默认是当前拖拽的节点层级【没有更改level之前的】
            // 如果遍历的层级和拖拽的层级不一样
            if (silblings[i].level != draggingNode.level) {
              catLevel = silblings[i].level
              this.updateChildrenNodeLevel(silblings[i])
            }

            // 如果拖拽的元素是遍历的元素，则修改他的排序，父ID，节点的ID
            this.updateNodes.push({catId: silblings[i].data.catId, sort: i, parentCid: pId, catLevel: catLevel})
          } else {
            // 如果是兄弟元素，只修改他的排序和节点的ID
            this.updateNodes.push({catId: silblings[i].data.catId, sort: i})
          }
          // 更新子节点的层级,如果拖拽的节点有子节点的话，那么他的子节点的层级也要变化
        }

        console.log('重新排序：', this.updateNodes)
        // 拖拽成功后，修改数据库数据，并将updateNodes 和maxLen 初始
        // batchSave  批量保存
      },

      /**
       * 递归设置子元素的层级
       * @param node
       */
      updateChildrenNodeLevel (node) {
        if (node.childNodes.length > 0) {
          // 如果存在子元素
          for (let i = 0; i < node.childNodes.length; i++) {
            // 子元素数据
            let childNode = node.childNodes[i].data
            // 设置子元素的catId,设置子元素的catLevel为node.childNodes[i].level
            this.updateNodes.push({catId: childNode.catId, catLevel: node.childNodes[i].level})
            this.updateChildrenNodeLevel(node.childNodes[i])
          }
        }
      },

      // 点击批量保存更改信息
      batchSave () {
        this.$http({
          url: this.$http.adornUrl('/product/category/update/sort'),
          method: 'POST',
          data: this.$http.adornData(this.updateNodes, false)
        }).then(({data}) => {
          // 更新成功后，刷新分类列表
          this.$message({
            type: 'success',
            message: '菜单拖拽成功!'
          })

          // 删除成功后重新刷新tree
          this.getMenu()

          // 定位在删除节点
          this.parentIds = this.pId
          this.updateNodes = []
          this.maxLen = 0
          // this.pId = 0
        })
      },

      // 批量删除选中的菜单
      batchDelete () {
        // 获取当前批量选中的节点数据
        let checkNodes = this.$refs.menuTree.getCheckedNodes()
        let delArr = []
        let delName = []
        for (let i = 0; i < checkNodes.length; i++) {
          delArr.push(checkNodes[i].catId)
          delName.push(checkNodes[i].name)
        }
        console.log('选中的节点数据', delArr)
        console.log('选中的节点数据名称', delName)
        // 调用删除方法批量删除
        this.$confirm(`是否批量删除【${delName}】菜单`, '提示', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning'
        }).then(() => {
          this.$http({
            url: this.$http.adornUrl('/product/category/delete'),
            method: 'POST',
            data: this.$http.adornData(delArr, false)
          }).then(({data}) => {
            this.$message({
              type: 'success',
              message: '菜单删除成功!'
            })
            // 删除成功后重新刷新tree
            this.getMenu()
          })
        }).catch(() => {
        })
      }

    },
    //监听属性 类似于data概念",
    computed: {},
    //监控data中的数据变化",
    watch: {},
    //方法集合",
    //methods: {},
    //生命周期 - 创建之前",数据模型未加载,方法未加载,html模板未加载
    beforeCreate () {
    },

    //生命周期 - 创建完成（可以访问当前this实例）",数据模型已加载，方法已加载,html模板已加载,html模板未渲染
    created () {
      this.getMenu()
    },
    //生命周期 - 挂载之前",html模板未渲染
    beforeMount () {

    },

    //生命周期 - 挂载完成（可以访问DOM元素）",html模板已渲染
    mounted () {

    },

    //生命周期 - 更新之前",数据模型已更新,html模板未更新
    beforeUpdate () {

    },
    //生命周期 - 更新之后",数据模型已更新,html模板已更新
    updated () {

    },
    //生命周期 - 销毁之前",
    beforeDestroy () {

    },
    destroyed () {

    },
    //生命周期 - 销毁完成",
    //如果页面有keep-alive缓存功能，这个函数会触发",
    activated () {

    }
  }
  // "http-get请求": {
  //   "prefix": "httpget",
  //     "body": [
  //     "this.\({",
  //     "url: this.\\$http.adornUrl(''),",
  //     "method: 'get',",
  //     "params: this.\\$http.adornParams({})",
  //     "}).then(({ data }) => {",
  //     "})"
  //   ],
  //     "description": "httpGET请求"
  // },
  // "http-post请求": {
  //   "prefix": "httppost",
  //     "body": [
  //     "this.\({",
  //     "url: this.\\$http.adornUrl(''),",
  //     "method: 'post',",
  //     "data: this.\\$http.adornData(data, false)",
  //     "}).then(({ data }) => { });"
  //   ],
  //     "description": "httpPOST请求"
  // }
  // }
</script>

<style>

</style>
